package com.kexilo.exception.domain;

import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Map;

/**
 * 异常记录抽象模型
 * 不依赖任何具体的异常实体，完全解耦
 * 
 * @author Kexilo
 */
public class ExceptionRecord implements Serializable {
    
    private static final long serialVersionUID = 1L;
    
    /**
     * 异常ID
     */
    private String exceptionId;
    
    /**
     * 链路追踪ID
     */
    private String traceId;
    
    /**
     * 异常类型
     */
    private String exceptionType;
    
    /**
     * 异常类名
     */
    private String exceptionClass;
    
    /**
     * 异常消息
     */
    private String exceptionMessage;
    
    /**
     * 异常堆栈信息
     */
    private String stackTrace;
    
    /**
     * 异常发生时间
     */
    private LocalDateTime occurTime;
    
    /**
     * 用户ID
     */
    private String userId;
    
    /**
     * 用户名称
     */
    private String userName;
    
    /**
     * 请求URL
     */
    private String requestUrl;
    
    /**
     * 请求方法
     */
    private String requestMethod;
    
    /**
     * 请求参数
     */
    private String requestParams;
    
    /**
     * 用户IP
     */
    private String userIp;
    
    /**
     * 用户代理
     */
    private String userAgent;
    
    /**
     * 浏览器类型
     */
    private String browserType;
    
    /**
     * 操作系统
     */
    private String operatingSystem;
    
    /**
     * 异常级别（ERROR, WARN, INFO等）
     */
    private String level;
    
    /**
     * 处理状态（PENDING, PROCESSING, RESOLVED, IGNORED）
     */
    private String status;
    
    /**
     * 异常来源（WEB, API, SCHEDULED, MESSAGE等）
     */
    private String source;
    
    /**
     * 业务模块
     */
    private String businessModule;
    
    /**
     * 异常标签（用于分类）
     */
    private String tags;
    
    /**
     * 额外信息（JSON格式）
     */
    private String extraInfo;
    
    /**
     * 处理备注
     */
    private String remark;
    
    /**
     * 创建时间
     */
    private LocalDateTime createTime;
    
    /**
     * 更新时间
     */
    private LocalDateTime updateTime;
    
    // 构造器
    public ExceptionRecord() {}
    
    public ExceptionRecord(String exceptionType, String exceptionMessage) {
        this.exceptionType = exceptionType;
        this.exceptionMessage = exceptionMessage;
        this.occurTime = LocalDateTime.now();
        this.createTime = LocalDateTime.now();
    }
    
    // Builder模式构造器
    public static Builder builder() {
        return new Builder();
    }
    
    public static class Builder {
        private ExceptionRecord record = new ExceptionRecord();
        
        public Builder exceptionId(String exceptionId) {
            record.exceptionId = exceptionId;
            return this;
        }
        
        public Builder traceId(String traceId) {
            record.traceId = traceId;
            return this;
        }
        
        public Builder exceptionType(String exceptionType) {
            record.exceptionType = exceptionType;
            return this;
        }
        
        public Builder exceptionClass(String exceptionClass) {
            record.exceptionClass = exceptionClass;
            return this;
        }
        
        public Builder exceptionMessage(String exceptionMessage) {
            record.exceptionMessage = exceptionMessage;
            return this;
        }
        
        public Builder stackTrace(String stackTrace) {
            record.stackTrace = stackTrace;
            return this;
        }
        
        public Builder occurTime(LocalDateTime occurTime) {
            record.occurTime = occurTime;
            return this;
        }
        
        public Builder userId(String userId) {
            record.userId = userId;
            return this;
        }
        
        public Builder userName(String userName) {
            record.userName = userName;
            return this;
        }
        
        public Builder requestUrl(String requestUrl) {
            record.requestUrl = requestUrl;
            return this;
        }
        
        public Builder requestMethod(String requestMethod) {
            record.requestMethod = requestMethod;
            return this;
        }
        
        public Builder requestParams(String requestParams) {
            record.requestParams = requestParams;
            return this;
        }
        
        public Builder userIp(String userIp) {
            record.userIp = userIp;
            return this;
        }
        
        public Builder userAgent(String userAgent) {
            record.userAgent = userAgent;
            return this;
        }
        
        public Builder browserType(String browserType) {
            record.browserType = browserType;
            return this;
        }
        
        public Builder operatingSystem(String operatingSystem) {
            record.operatingSystem = operatingSystem;
            return this;
        }
        
        public Builder level(String level) {
            record.level = level;
            return this;
        }
        
        public Builder status(String status) {
            record.status = status;
            return this;
        }
        
        public Builder source(String source) {
            record.source = source;
            return this;
        }
        
        public Builder businessModule(String businessModule) {
            record.businessModule = businessModule;
            return this;
        }
        
        public Builder tags(String tags) {
            record.tags = tags;
            return this;
        }
        
        public Builder extraInfo(String extraInfo) {
            record.extraInfo = extraInfo;
            return this;
        }
        
        public Builder extraInfo(Map<String, Object> extraMap) {
            if (extraMap != null && !extraMap.isEmpty()) {
                // 这里可以使用JSON序列化，简化示例直接toString
                record.extraInfo = extraMap.toString();
            }
            return this;
        }
        
        public Builder remark(String remark) {
            record.remark = remark;
            return this;
        }
        
        public Builder createTime(LocalDateTime createTime) {
            record.createTime = createTime;
            return this;
        }
        
        public Builder updateTime(LocalDateTime updateTime) {
            record.updateTime = updateTime;
            return this;
        }
        
        public ExceptionRecord build() {
            if (record.occurTime == null) {
                record.occurTime = LocalDateTime.now();
            }
            if (record.createTime == null) {
                record.createTime = LocalDateTime.now();
            }
            if (record.status == null) {
                record.status = "PENDING";
            }
            if (record.level == null) {
                record.level = "ERROR";
            }
            return record;
        }
    }
    
    // Getters and Setters
    public String getExceptionId() { return exceptionId; }
    public void setExceptionId(String exceptionId) { this.exceptionId = exceptionId; }
    
    public String getTraceId() { return traceId; }
    public void setTraceId(String traceId) { this.traceId = traceId; }
    
    public String getExceptionType() { return exceptionType; }
    public void setExceptionType(String exceptionType) { this.exceptionType = exceptionType; }
    
    public String getExceptionClass() { return exceptionClass; }
    public void setExceptionClass(String exceptionClass) { this.exceptionClass = exceptionClass; }
    
    public String getExceptionMessage() { return exceptionMessage; }
    public void setExceptionMessage(String exceptionMessage) { this.exceptionMessage = exceptionMessage; }
    
    public String getStackTrace() { return stackTrace; }
    public void setStackTrace(String stackTrace) { this.stackTrace = stackTrace; }
    
    public LocalDateTime getOccurTime() { return occurTime; }
    public void setOccurTime(LocalDateTime occurTime) { this.occurTime = occurTime; }
    
    public String getUserId() { return userId; }
    public void setUserId(String userId) { this.userId = userId; }
    
    public String getUserName() { return userName; }
    public void setUserName(String userName) { this.userName = userName; }
    
    public String getRequestUrl() { return requestUrl; }
    public void setRequestUrl(String requestUrl) { this.requestUrl = requestUrl; }
    
    public String getRequestMethod() { return requestMethod; }
    public void setRequestMethod(String requestMethod) { this.requestMethod = requestMethod; }
    
    public String getRequestParams() { return requestParams; }
    public void setRequestParams(String requestParams) { this.requestParams = requestParams; }
    
    public String getUserIp() { return userIp; }
    public void setUserIp(String userIp) { this.userIp = userIp; }
    
    public String getUserAgent() { return userAgent; }
    public void setUserAgent(String userAgent) { this.userAgent = userAgent; }
    
    public String getBrowserType() { return browserType; }
    public void setBrowserType(String browserType) { this.browserType = browserType; }
    
    public String getOperatingSystem() { return operatingSystem; }
    public void setOperatingSystem(String operatingSystem) { this.operatingSystem = operatingSystem; }
    
    public String getLevel() { return level; }
    public void setLevel(String level) { this.level = level; }
    
    public String getStatus() { return status; }
    public void setStatus(String status) { this.status = status; }
    
    public String getSource() { return source; }
    public void setSource(String source) { this.source = source; }
    
    public String getBusinessModule() { return businessModule; }
    public void setBusinessModule(String businessModule) { this.businessModule = businessModule; }
    
    public String getTags() { return tags; }
    public void setTags(String tags) { this.tags = tags; }
    
    public String getExtraInfo() { return extraInfo; }
    public void setExtraInfo(String extraInfo) { this.extraInfo = extraInfo; }
    
    public String getRemark() { return remark; }
    public void setRemark(String remark) { this.remark = remark; }
    
    public LocalDateTime getCreateTime() { return createTime; }
    public void setCreateTime(LocalDateTime createTime) { this.createTime = createTime; }
    
    public LocalDateTime getUpdateTime() { return updateTime; }
    public void setUpdateTime(LocalDateTime updateTime) { this.updateTime = updateTime; }
    
    /**
     * 是否为系统级异常
     */
    public boolean isSystemException() {
        return "SYSTEM".equalsIgnoreCase(this.exceptionType) ||
               "NullPointerException".equals(this.exceptionClass) ||
               "OutOfMemoryError".equals(this.exceptionClass);
    }
    
    /**
     * 是否为业务异常
     */
    public boolean isBusinessException() {
        return "BUSINESS".equalsIgnoreCase(this.exceptionType) ||
               "BusinessException".equals(this.exceptionClass);
    }
    
    /**
     * 是否为高优先级异常
     */
    public boolean isHighPriority() {
        return "ERROR".equals(this.level) && 
               (isSystemException() || this.exceptionMessage.contains("数据库"));
    }
    
    /**
     * 是否已处理
     */
    public boolean isResolved() {
        return "RESOLVED".equals(this.status) || "IGNORED".equals(this.status);
    }
    
    @Override
    public String toString() {
        return "ExceptionRecord{" +
                "exceptionId='" + exceptionId + '\'' +
                ", traceId='" + traceId + '\'' +
                ", exceptionType='" + exceptionType + '\'' +
                ", exceptionClass='" + exceptionClass + '\'' +
                ", exceptionMessage='" + exceptionMessage + '\'' +
                ", occurTime=" + occurTime +
                ", level='" + level + '\'' +
                ", status='" + status + '\'' +
                '}';
    }
    
    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        ExceptionRecord that = (ExceptionRecord) obj;
        return exceptionId != null ? exceptionId.equals(that.exceptionId) : 
               (traceId != null && traceId.equals(that.traceId));
    }
    
    @Override
    public int hashCode() {
        return exceptionId != null ? exceptionId.hashCode() : 
               (traceId != null ? traceId.hashCode() : super.hashCode());
    }
}
